﻿// ------------------------------------------------------------------------------
// <copyright file="Menu.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.
//
//    This program is free software; you can redistribute it and/or
//    modify it under the terms of the GNU General Public License
//    as published by the Free Software Foundation version 2
//    of the License.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    http://www.gnu.org/licenses/gpl-2.0.html
//
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.Controls
{
    using System.Collections.Generic;
    using Windows.UI;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;

    /// <summary>
    /// Menu class
    /// </summary>
    public class Menu : Control
    {
        /// <summary>
        /// Pointer Over Background value dependency property
        /// </summary>
        public static readonly DependencyProperty PointerOverBackgroundProperty =
            DependencyProperty.Register("PointerOverBackground", typeof(SolidColorBrush), typeof(Menu), new PropertyMetadata(new SolidColorBrush(Colors.Transparent)));
        
        /// <summary>
        /// Pressed Background value dependency property
        /// </summary>
        public static readonly DependencyProperty PressedBackgroundProperty =
            DependencyProperty.Register("PressedBackground", typeof(SolidColorBrush), typeof(Menu), new PropertyMetadata(new SolidColorBrush(Colors.Transparent)));
        
        /// <summary>
        /// Separator color dependency property
        /// </summary>
        public static readonly DependencyProperty SeparatorColorProperty =
            DependencyProperty.Register("SeparatorColor", typeof(SolidColorBrush), typeof(Menu), new PropertyMetadata(Menu.MenuSeparatorColor));

        /// <summary>
        /// Separator thickness dependency property
        /// </summary>
        public static readonly DependencyProperty SeparatorThicknessProperty =
            DependencyProperty.Register("SeparatorThickness", typeof(double), typeof(Menu), new PropertyMetadata(Menu.MenuSeparatorThickness));

        /// <summary>
        /// Menu pointer over color
        /// </summary>
        public static readonly SolidColorBrush MenuPointerOverBackground = new SolidColorBrush(Colors.LightGray);

        /// <summary>
        /// Menu pressed color
        /// </summary>
        public static readonly SolidColorBrush MenuPressedBackground = new SolidColorBrush(Colors.Gray);

        /// <summary>
        /// Menu separator color
        /// </summary>
        public static readonly SolidColorBrush MenuSeparatorColor = new SolidColorBrush(Colors.LightGray);

        /// <summary>
        /// Menu separator thickness
        /// </summary>
        public static readonly double MenuSeparatorThickness = 2.0;

        /// <summary>
        /// Menu background color
        /// </summary>
        public static readonly SolidColorBrush MenuBackground = new SolidColorBrush(Colors.White);

        /// <summary>
        /// Menu foreground color
        /// </summary>
        public static readonly SolidColorBrush MenuForeground = new SolidColorBrush(Colors.Black);

        /// <summary>
        /// Menu border color
        /// </summary>
        public static readonly SolidColorBrush MenuBorderColor = new SolidColorBrush(Colors.Black);

        /// <summary>
        /// Menu border thickness
        /// </summary>
        public static readonly double MenuBorderThickness = 2.0;

        /// <summary>
        /// Menu Items dependency property
        /// </summary>
        internal static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(List<IMenuItem>), typeof(Menu), new PropertyMetadata(null));

        /// <summary>
        /// The triggering source
        /// </summary>
        private FrameworkElement relativeSource;

        /// <summary>
        /// The popup manager
        /// </summary>
        private PopupManager popupManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="Menu" /> class 
        /// </summary>
        public Menu()
        {
            this.Items = new List<IMenuItem>();

            this.SeparatorColor = Menu.MenuSeparatorColor;
            this.SeparatorThickness = Menu.MenuSeparatorThickness;
            this.Background = Menu.MenuBackground;
            this.Foreground = Menu.MenuForeground;
            this.FontFamily = new FontFamily("Segoe UI Light");
            this.FontSize = 15;
            this.BorderBrush = Menu.MenuBorderColor;
            this.BorderThickness = new Thickness(Menu.MenuBorderThickness);
            this.HorizontalContentAlignment = HorizontalAlignment.Center;
            this.PointerOverBackground = Menu.MenuPointerOverBackground;
            this.PressedBackground = Menu.MenuPressedBackground;

            this.DefaultStyleKey = typeof(Menu);
        }

        /// <summary>
        /// Menu invoked event handler
        /// </summary>
        public event MenuItemInvokedEventHandler MenuItemInvoked;

        /// <summary>
        /// Gets or sets Separator thickness property.
        /// </summary>
        /// <value>
        /// The Separator thickness.
        /// </value>
        public double SeparatorThickness
        {
            get
            {
                return (double)this.GetValue(SeparatorThicknessProperty);
            }

            set
            {
                this.SetValue(SeparatorThicknessProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Separator color property.
        /// </summary>
        /// <value>
        /// The Separator color.
        /// </value>
        public SolidColorBrush SeparatorColor
        {
            get
            {
                return (SolidColorBrush)this.GetValue(SeparatorColorProperty);
            }

            set
            {
                this.SetValue(SeparatorColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Pointer Over Background property.
        /// </summary>
        /// <value>
        /// The Pointer Over Background.
        /// </value>
        public SolidColorBrush PointerOverBackground
        {
            get
            {
                return (SolidColorBrush)this.GetValue(PointerOverBackgroundProperty);
            }

            set
            {
                this.SetValue(PointerOverBackgroundProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Pressed Background property.
        /// </summary>
        /// <value>
        /// The Pressed Background.
        /// </value>
        public SolidColorBrush PressedBackground
        {
            get
            {
                return (SolidColorBrush)this.GetValue(PressedBackgroundProperty);
            }

            set
            {
                this.SetValue(PressedBackgroundProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets menu items
        /// </summary>
        public List<IMenuItem> Items
        {
            get
            {
                return (List<IMenuItem>)this.GetValue(ItemsProperty);
            }

            set
            {
                this.SetValue(ItemsProperty, value);
            }
        }

        /// <summary>
        /// Shows menu
        /// </summary>
        /// <param name="relativeSource">The source triggering the menu</param>
        /// <param name="alignment">Menu alignment with respect to source</param>
        public void Show(FrameworkElement relativeSource, PopupAlignment alignment)
        {
            this.relativeSource = relativeSource;

            StackPanel panel = new StackPanel();

            Border border = new Border();
            border.BorderThickness = this.BorderThickness;
            border.BorderBrush = this.BorderBrush;
            border.Background = this.Background;
            border.Child = panel;

            foreach (IMenuItem menuItem in this.Items)
            {
                MenuItem itemControl = new MenuItem(menuItem);

                Control xamlItem = menuItem as Control;

                itemControl.Background = xamlItem.Background;

                if (itemControl.Style != xamlItem.Style)
                {
                    itemControl.Style = xamlItem.Style;
                }

                if (itemControl.FontFamily != xamlItem.FontFamily)
                {
                    itemControl.FontFamily = xamlItem.FontFamily;
                }

                if (itemControl.FontSize != xamlItem.FontSize)
                {
                    itemControl.FontSize = xamlItem.FontSize;
                }

                if (itemControl.FontStretch != xamlItem.FontStretch)
                {
                    itemControl.FontStretch = xamlItem.FontStretch;
                }

                if (itemControl.FontStyle != xamlItem.FontStyle)
                {
                    itemControl.FontStyle = xamlItem.FontStyle;
                }

                if (itemControl.FontWeight.Weight != xamlItem.FontWeight.Weight)
                {
                    itemControl.FontWeight = xamlItem.FontWeight;
                }

                if (itemControl.Foreground != xamlItem.Foreground)
                {
                    itemControl.Foreground = xamlItem.Foreground;
                }

                if (itemControl.HorizontalContentAlignment == xamlItem.HorizontalContentAlignment)
                {
                    itemControl.HorizontalContentAlignment = this.HorizontalContentAlignment;
                }
                else
                {
                    itemControl.HorizontalContentAlignment = xamlItem.HorizontalContentAlignment;
                }

                if (xamlItem is MenuItem)
                {
                    MenuItem textXamlItem = xamlItem as MenuItem;

                    itemControl.Tapped += this.OnMenuItemTapped;

                    if (textXamlItem.PointerOverBackground != null && textXamlItem.PointerOverBackground.Color != Colors.Transparent && itemControl.PointerOverBackground != textXamlItem.PointerOverBackground)
                    {
                        itemControl.PointerOverBackground = textXamlItem.PointerOverBackground;
                    }
                    else
                    {
                        itemControl.PointerOverBackground = this.PointerOverBackground;
                    }

                    if (textXamlItem.PressedBackground != null && textXamlItem.PressedBackground.Color != Colors.Transparent && itemControl.PressedBackground != textXamlItem.PressedBackground)
                    {
                        itemControl.PressedBackground = textXamlItem.PressedBackground;
                    }
                    else
                    {
                        itemControl.PressedBackground = this.PressedBackground;
                    }
                }

                if (xamlItem is MenuSeparator)
                {
                    MenuSeparator separatorXamlItem = xamlItem as MenuSeparator;

                    if (separatorXamlItem.SeparatorColor != null && separatorXamlItem.SeparatorColor != Menu.MenuSeparatorColor && itemControl.SeparatorColor != separatorXamlItem.SeparatorColor)
                    {
                        itemControl.SeparatorColor = separatorXamlItem.SeparatorColor;
                    }
                    else
                    {
                        itemControl.SeparatorColor = this.SeparatorColor;
                    }

                    if (separatorXamlItem.SeparatorThickness != 0 && itemControl.SeparatorThickness != separatorXamlItem.SeparatorThickness)
                    {
                        itemControl.SeparatorThickness = separatorXamlItem.SeparatorThickness;
                    }
                    else
                    {
                        itemControl.SeparatorThickness = this.SeparatorThickness;
                    }

                    itemControl.MinHeight = 20;
                }

                panel.Children.Add(itemControl);
            }

            ContentControl control = new ContentControl();
            control.Content = border;

            control.Style = this.Style;
            control.FontFamily = this.FontFamily;
            control.FontSize = this.FontSize;
            control.FontStretch = this.FontStretch;
            control.FontStyle = this.FontStyle;
            control.FontWeight = this.FontWeight;
            control.Foreground = this.Foreground;
            control.Background = this.Background;

            this.popupManager = PopupManager.Open(this.relativeSource, control, alignment);
        }

        /// <summary>
        /// Called before the Tapped event occurs
        /// </summary>
        /// <param name="sender">The source</param>
        /// <param name="e">Event data for the event</param>
        private void OnMenuItemTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
        {
            if (this.MenuItemInvoked != null)
            {
                this.MenuItemInvoked(this, (sender as MenuItem).XMALMenuItem as MenuItem);
            }

            this.OnTapped(e);

            this.popupManager.Close();
        }
    }
}
